/*
    Copyright 2006-2012 Patrik Jonsson, sunrise@familjenjonsson.org

    This file is part of Sunrise.

    Sunrise is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.

    Sunrise is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Sunrise.  If not, see <http://www.gnu.org/licenses/>.

*/

/** \file

    Contains the calculate_SED function that selects the proper grain
    model class in lieu of a virtual call. */

#ifndef __grain_model_hack__
#define __grain_model_hack__

#include "grain_model.h"
#include "grain_collection_grain_model.h"
#include "dl07_template_grain_model.h"
#include "baes_grain_model.h"
#include "blackbody_grain.h"
#include "molecule_grain_model.h"

#ifndef __grain_model__
#error grain_model_hack.h must be included after grain_model.h
#endif

#ifndef __grain_collection_grain_model__
#error grain_model_hack.h must be included after grain_collection_grain_model.h
#endif

#ifndef __dl07_template_grain_model__
#error grain_model_hack.h must be included after dl07_template_grain_model.h
#endif

#ifndef __blackbody_grain__
#error grain_model_hack.h must be included after blackbody_grain.h
#endif

#ifndef __baes_grain_model__
#error grain_model_hack.h must be included after baes_grain_model.h
#endif

#ifndef __molecule_grain_model__
#error grain_model_hack.h must be included after molecule_grain_model.h
#endif

/** Calculate the SED for the grain model by delegating to the correct
    grain_model class based on the type of the grain model. This
    really should be done with virtual function, but because the
    intensity is an expression template object, we can't. Instead we
    have to do the unspeakable and do a manual virtual
    dispatch. Luckily the types are few -- but they keep growing... */
template <template<class> class chromatic_policy, typename T_rng_policy>
template<typename T>
void mcrx::grain_model<chromatic_policy, T_rng_policy>::
calculate_SED(const blitz::ETBase<T>& intensity, const array_1& m_dust,
	      array_2& sed, array_2* temp) const
{
  // we put grain_collection_grain_model last in this list because
  // several of the grain types are actually subclasses of it, so
  // otherwise we'll call the wrong function.
  try {
    dynamic_cast<const dl07_template_grain_model<chromatic_policy, 
						 T_rng_policy>&>
      (*this).calculate_SED_virtual(intensity, m_dust, sed, temp);
  }
  catch (std::bad_cast&) {
    try {
      dynamic_cast<const baes_grain_model<chromatic_policy, 
					  T_rng_policy>&>
	(*this).calculate_SED_virtual(intensity, m_dust, sed, temp);
    }
    catch (std::bad_cast&) {
      try {
	dynamic_cast<const blackbody_grain_model<chromatic_policy, 
						 T_rng_policy>&>
	  (*this).calculate_SED_virtual(intensity, m_dust, sed, temp);
      }
      catch (std::bad_cast&) {      
	try {
	  dynamic_cast<const molecule_grain_model<chromatic_policy,
						  T_rng_policy>&>
	    (*this).calculate_SED_virtual(intensity, m_dust, sed, temp);
	}
	catch (std::bad_cast&) {      
	  try {
	    dynamic_cast<const grain_collection_grain_model<chromatic_policy, 
							    T_rng_policy>&>
	      (*this).calculate_SED_virtual(intensity, m_dust, sed, temp);
	  }
	  catch (std::bad_cast&) {      
	    std::cerr << "Unimplemented virtual dispatch hack in grain_model::calculate_SED" << endl;
	    throw;
	  }
	}
      }
    }
  }
}

#endif
